#pragma once
#include <omnetpp.h>
#include <queue>
#include "ib_cluster/message/messages_m.h"
#include "ib_m.h"

using namespace ai_sim;

/**
 * @brief Inherits from FlowMsg;
 * Sent via virtual switch when a package finishes
 * 
 */
class VirtualFlowMsg : public FlowMsg
{
  public:
    VirtualFlowMsg(const char *name=nullptr, short kind=0) : FlowMsg(name,kind) {}
};

/**
 * @brief The virtual app;
 * Accepts request from GPU;
 * Forwards messages to GPU
 * 
 */
class IBVirtualApp : public omnetpp::cSimpleModule
{
    private:
    /**
     * @brief MTU length in bytes
     * 
     */
    static constexpr unsigned msgMtuLen_B_ = 2048;

    /**
     * @brief Current IBAppMsg being sent;
     * nullptr if noting being sent
     * 
     */
    VirtualFlowMsg* msg_being_sent_ = nullptr;

    /**
     * @brief Queue holding IBAppMsg to be sent
     * 
     */
    std::queue<FlowMsg*> AppMsgQueue;

    /**
     * @brief sends IBAppMsg if queue non empty && not sending
     * 
     */
    void trySendNext();
    
    /**
     * @brief Converts FlowMsg to IBAppMsg
     * 
     * @param flow_m Input FlowMsg
     * @return IBAppMsg* 
     */
    IBAppMsg* toIBAppMsg(const FlowMsg* flow_m) const;
    VirtualFlowMsg* toVirtualFlowMsg(FlowMsg* flow_m);
    virtual ~IBVirtualApp();

    protected:
    virtual void initialize() override;
    virtual void handleMessage(omnetpp::cMessage* msg) override;
    virtual void finish();
};
